import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * Класс содержит методы с запросами на чтение
 * из базы данных.
 * @author tub
 */
public class BaseReader
{
    public BaseReader(Connection conn)
    {
        this.conn = conn;
    }

    /**
     * Содержит всю информацию о лейбле.
     * Используется для отображения на страницах лейблов.
     * @param req Запрос с типом Label, содержащий id Лейбла
     * @return возвращает объект Label, заполненный информацией
     * @throws SQLException
     */
    public Label readLabel(Request req) throws SQLException
    {
        String ID = req.getReq();   //Строка с ID лейбла

        //Запрос на получение названия
        //даты основания, информации о лейбле,
        //и списка id изданных на нем релизов
        String label =
                "SELECT l.title, l.birthday, rp.release_id, l.info" +
                "FROM label l, release_publisher rp" +
                "WHERE l.id = rp.label_id" +
                "AND l.id = ?";
        PreparedStatement labelStat = conn.prepareStatement(label);
        labelStat.setString(1, ID);

        //Получение названий дочерних лейблов
        String sublabels =
                "SELECT title" +
                "FROM label" +
                "WHERE parent_label_id = ?";
        PreparedStatement sublabelsStat = conn.prepareStatement(sublabels);
        sublabelsStat.setString(1, ID);

        ResultSet rs = sublabelsStat.executeQuery();
        String bufLabels = rs.getString(1);      //Сохранение названий дочерних лейблов

        //Выполнение подготовленного запроса на получение основной инфы
        //и инициализация списка в котором будет храниться информация о релизах
        rs = labelStat.executeQuery();
        ArrayList<Release> releases = null;

        //Получение из набора данных id релизов
        //и создание объектов Release с вызовом
        //метода, для добавления в них информации
        while (rs.next())
            releases.add(readRelease(new Request(ReqType.RELEASE, rs.getString(3))));

        Release[] bufReleases = (Release[]) releases.toArray();     //Конвертация списка в обычный массив

        return new Label(ID, rs.getString(1), rs.getString(2), bufLabels, bufReleases, rs.getString(4));
    }

    public void readTracklist(Request req) throws SQLException
    {
        Release release = readRelease(req);

        String ID = req.getReq();   //Строка с ID релиза
        String tracklist =
                "SELECT t.title, a.performer_id, a.title, m.position, m.disc_number, m.length" +
                "FROM track t, track_performer tp, alias a, metadata m" +
                "WHERE t.id = tp.track_id" +
                "AND tp.alias_id = alias.id" +
                "AND t.id = m.track_id" +
                "AND m.release_id = ?";

        PreparedStatement trackStat = conn.prepareStatement(tracklist);
        trackStat.setString(1, ID);

        ResultSet rs = trackStat.executeQuery();

        ArrayList<Performer> performer = null;
        String title = "", position = "", disc_number = "", length = "";

        while (rs.next())
        {
            title = rs.getString(1);
            performer.add(new Performer(rs.getString(2), rs.getString(3)));
            position = rs.getString(4);
            disc_number = rs.getString(5);
            disc_number = rs.getString(6);
        }

        Performer[] bufPerformer = (Performer[]) performer.toArray();

        //return new Tracklist(ID, title );
    }

    public Track readTrack(Request trackReq, Request releaseReq) throws SQLException
    {
        String ID = trackReq.getReq();   //Строка с ID трека
        String releaseID = releaseReq.getReq(); //Строка с ID релиза
        String track =
                "SELECT t.title, a.performer_id, a.title, m.position, m.disc_number, m.length" +
                "FROM track t, track_performer tp, alias a, metadata m" +
                "WHERE t.id = tp.track_id" +
                "AND tp.alias_id = alias.id" +
                "AND t.id = m.track_id" +
                "AND t.id = ?" +
                "AND m.release_id = ?";

        PreparedStatement trackStat = conn.prepareStatement(track);
        trackStat.setString(1, ID);
        trackStat.setString(2, releaseID);

        ResultSet rs = trackStat.executeQuery();

        ArrayList<Performer> performer = null;

        while(rs.next())
            performer.add(new Performer(rs.getString(2), rs.getString(3)));

        Performer[] bufPerformer = (Performer[]) performer.toArray();

        return new Track(ID, rs.getString(1), bufPerformer, rs.getString(4), rs.getString(5), rs.getString(6));
    }

    /**
     * Возвращает объект Release с полной информацией,
     * в т.ч. с массивами объектов Label и Performer, содержищими
     * лишь названия и id, для получения полной информации
     * @param req Запрос с типом Release, содержащий id релиза
     * @return возвращает объект Release, заполненный информацией
     * @throws SQLException
     */
    public Release readRelease(Request req) throws SQLException
    {
        String ID = req.getReq();
        
        //Запрос на получение всей необходимой информации
        //a.performer_id, a.title - параметры для создания
        //объектов типа Performer с сокращенным кол-вом
        //информации, достаточной для получения полной
        //l.id, l.title - параметры для создания
        //объектов типа Label с сокращенным кол-вом инфы
        String release =
                "SELECT r.catalog, a.performer_id, a.title, r.title, f.title, r.released, g.title, l.id, r.country, r.info" +
                "FROM release r, label l, genre g, format f, alias a, release_publisher rp" +
                "WHERE r.id = release_genre.release_id" +
                "AND release_genre.genre_id = g.id" +
                "AND r.id = release_format.release_id" +
                "AND release_format.format_id = f.id" +
                "AND r.id = rp.release_id" +
                "AND rp.label_id = l.id" +
                "AND r.id = release_performer.release_id" +
                "AND release_performer.alias_id = a.id" +
                "AND r.id = ?";

        PreparedStatement releaseStat = conn.prepareStatement(release);
        releaseStat.setString(1, ID);
        ResultSet rs = releaseStat.executeQuery();

        //Инициализация строк и списков для размещения в
        //них параметров, необходимых для создания объекта Release
        String format = "", genre = "";
        ArrayList<Performer> performer = null;
        ArrayList<Label> label = null;

        //Получение из набора необходимых строк
        while (rs.next())
        {
            performer.add(new Performer(rs.getString(2), rs.getString(3)));
            format = (format + ", " + rs.getString(5));
            genre = (genre + ", " + rs.getString(7));
            label.add(new Label(rs.getString(8), rs.getString(9)));
        }

        //преобразование списков в массивы
        Performer[] bufPerformer = (Performer[]) performer.toArray();
        Label[] bufLabel = (Label[]) label.toArray();

        return new Release(ID, rs.getString(1), bufPerformer, rs.getString(4), format, rs.getString(6), genre, bufLabel, rs.getString(9), rs.getString(10));
    }

    public Performer readPerformer(Request req) throws SQLException
    {
        String ID = req.getReq();
        String performer =
                "SELECT c.human_id, a.title, rp.release_id" +
                "FROM release_performer rp, alias a, performer p, composition c" +
                "WHERE p.id = ?" +
                "AND a.performer_id = p.id" +
                "AND rp.alias_id = a.id" +
                "AND c.performer_id = p.id";

        PreparedStatement performerStat = conn.prepareStatement(performer);
        performerStat.setString(1, ID);
        ResultSet rs = performerStat.executeQuery();

        String alias = "";
        ArrayList<Human> human = null;
        ArrayList<Release> release = null;

        while (rs.next())
        {
            human.add(readHuman(new Request(ReqType.HUMAN, rs.getString(1))));
            alias = (alias + ", " + rs.getString(2));
            release.add(readRelease(new Request(ReqType.RELEASE, rs.getString(3))));
        }

        Human[] bufHuman = (Human[]) human.toArray();
        Release[] bufRelease = (Release[]) release.toArray();

        return new Performer(ID, "", bufHuman, alias, bufRelease);
    }

    public Human readHuman(Request req) throws SQLException
    {
        String ID = req.getReq();
        String human =
                "SELECT name, male, birthday, death_date, country" +
                "FROM human" +
                "WHERE id = ?";

        PreparedStatement humanStat = conn.prepareStatement(human);
        humanStat.setString(1, ID);
        ResultSet rs = humanStat.executeQuery();

        return new Human(ID, rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5));
    }

    public User readUser(Request req) throws SQLException
    {
        String ID = req.getReq();
        String user =
                "SELECT nick, human_id, status, registred" +
                "FROM user" +
                "WHERE u.id = ?";

        PreparedStatement userStat = conn.prepareStatement(user);
        userStat.setString(1, ID);
        ResultSet rs = userStat.executeQuery();

        Human human = readHuman(new Request(ReqType.HUMAN, rs.getString(2)));
        return new User(ID, rs.getString(1), human, rs.getString(3), rs.getString(4));
    }

   private Connection conn;
}
